/**
 * @file heap_test_senya.h
 *
 * @brief test for heap_senya
 *
 */

#include <iostream>
#include <fstream>
#include <windows.h>
#include <set>

//#include "../../src/ludmila/heap_ludmila.h"
//#include "../../src/ludmila/heap_ludmila.cpp"
#include "../../src/senya/heap_senya.h"

#define tr(cont, it) for(typeof((cont).begin()) it=(cont).begin(); it != (cont).end(); ++it)

using namespace std;

int easytest(heap876 *ph) {
	cout << ph->get_name() << ' ' << ph->get_volume() << std::endl;
	int *arr = (int *) ph->alloc(100*sizeof(int), 'wsef');
	for(int i=0; i<100; ++i)
		arr[i] = i;

	//((heap_senya *)ph)->print_blocks();
	return 0;
}

typedef pair<int, int> ii;
typedef pair<int, ii> iii;
int ALLOCS = 10000;
const int MAX_ALLOC = 1000;

void test(heap876 *ph) {
	void *ptr[ALLOCS];
	set< iii > Q;
	cout << "performance (" << ALLOCS << " allocs): " << endl;
	cout << "creating test" << endl;
	for (int i=0; i < ALLOCS; ++i) {
		iii a(rand()%ALLOCS, ii(rand()%MAX_ALLOC + 1, i));
		iii b(a.first + rand()%ALLOCS + 1, ii(0, i));
		Q.insert(a);
		Q.insert(b);
	}

	double deltaTime;
    static __int64 gTime,gLastTime;
	__int64 freq;

	cout << "start test" << endl;
	QueryPerformanceCounter((LARGE_INTEGER *)&gLastTime);
    tr(Q, it) {
    	if(it->second.first)
    		ptr[it->second.second] = ph->alloc(it->second.first);
    	else
			ph->free(ptr[it->second.second]);
    }

	QueryPerformanceCounter((LARGE_INTEGER *)&gTime);
	QueryPerformanceFrequency((LARGE_INTEGER *)&freq);
    deltaTime = (double)((double)(gTime - gLastTime)/(double)freq);
	cout << "test finished" << endl;
	cout << "TIME = " << deltaTime << endl;
}

void test_poisoning(heap876 *ph) {
	cout << "alloc_debug / poisoning: ";

	int bl_size = 1000;
	int ints = bl_size/sizeof(int);

	int *ptr = (int *)ph->alloc(1000), *ptr2;
	int *end = ptr + ints;
	ph->free(ptr);

	for(int *p = ptr+40; p<end; ++p)
		*p = rand();

	if(ptr2 = (int *)ph->alloc(1000)) {
		if(ptr2 == ptr)
			cout << "failed" << endl;
		else {
			cout << "something strange:" << endl;
			cout << "ptr = alloc(1000)" << endl;
			cout << "free(ptr)" << endl;
			cout << "ptr2 = alloc(1000)" << endl;
			cout << "and after that ptr != ptr2" << endl;
		}
		return;
	} else {
		cout << "OK" << endl;
	}
}

void test_badfree(heap876 *ph) {
	cout << "bad free: ";

	int *ptr = (int *)ph->alloc(1000);

	ph->free(0);
	ph->free(ptr - 100);
	ph->free(ptr + 1000);
	ph->free(ptr + 3);

	int *ptr2 = (int *)ph->alloc(1000);
	ph->free(ptr);

	ph->free(0);
	ph->free(ptr - 100);
	ph->free(ptr + 1000);
	ph->free(ptr + 3);

	ph->free(ptr2);

	ph->free(0);
	ph->free(ptr - 100);
	ph->free(ptr + 1000);
	ph->free(ptr + 3);

	cout << "OK" << endl;
}

const int t_num = 10;
int main() {
	heap_senya h1(10000, heap876::alloc_debug);
	test_poisoning(&h1);

	heap_senya h2(10000, heap876::alloc_debug);
	test_badfree(&h2);

	heap_senya h3(1000000000, heap876::alloc_simple);
	test(&h3);
/*
	HANDLE threadlist[t_num];

	for (int i = 0; i < t_num; i++)
	{
		threadlist[i] = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)(test), &h, 0, 0);
	}
	WaitForMultipleObjects(t_num, threadlist, TRUE, INFINITE);
*/
	return 0;
}
